<template>
  <div class="gantt-timeline">
    <div
        class="gantt-timeline-padding_block"
        :style="{ width: paddingWidth + 'px' }"
    ></div>
    <template v-for="(day, index) in allDayBlocks" :key="index">
      <div
          class="gantt-timeline-block"
          :style="{ width: getTimeScales(day).length * cellWidth + 'px' }"
          v-if="!isYearOrGreaterScale(scale)"
      >
        <slot :day="day" :getTimeScales="getTimeScales">
          <div class="gantt-timeline-day" :style="heightStyle">
            {{ format(day, "MM/dd") }}
          </div>
          <div
              v-if="!isDayScale"
              class="gantt-timeline-scale"
              :style="heightStyle"
          >
            <div
                v-for="(time, index) in getTimeScales(day)"
                :key="index"
                :style="cellWidthStyle"
            >
              {{ scale >= 60 ? format(time, "HH") : format(time, "HH:mm") }}
            </div>
          </div>
        </slot>
      </div>
    </template>
    <template v-for="(year, yIndex) in yearsArray" :key="yIndex + 'year'">
      <div class="gantt-timeline-block"
           :style="{ width: year.month.length * cellWidth + 'px' }"
           v-if="isYearOrGreaterScale(scale)"
      >
        <div class="gantt-timeline-year" :style="heightStyle">
          {{ year.year }}
        </div>
        <div class="gantt-timeline-month" :style="{
              ...heightStyle,
            }"
        >
          <div
              class="gantt-timeline-scale"
          >
            <template v-for="(month, mIndex) in year.month" :key="mIndex">
              <slot :day="month" :getTimeScales="getTimeScales">
                <div :style="cellWidthStyle">
                  {{ month.month }}
                </div>
              </slot>
            </template>

          </div>

        </div>


      </div>

    </template>
    <!--                {{ format(day, "MM") }}-->

  </div>
</template>

<script lang="ts" setup>
import {computed, PropType} from 'vue';
import dayjs from 'dayjs';
import {
  addDays,
  startOfDay,
  endOfDay,
  startOfHour,
  addHours,
  isBefore,
  isEqual,
  isSameDay,
  format,
  parseISO,
  isWithinInterval,
  addMinutes
} from 'date-fns';

import {
  isDayScale as _isDayScale,
  MINUTE_OF_ONE_DAY,
  getBeginTimeOfTimeLine
} from '@/utils/timeLineUtils.ts';

const START_DAY = Symbol();
const MIDDLE_DAY = Symbol();
const END_DAY = Symbol();

const props = defineProps({
  start: {
    type: Object as PropType<dayjs.Dayjs>,
    required: true
  },
  end: {
    type: Object as PropType<dayjs.Dayjs>,
    required: true
  },
  cellWidth: {
    type: Number,
    required: true
  },
  titleHeight: {
    type: Number,
    required: true
  },
  scale: {
    type: Number,
    required: true
  },
  endTimeOfRenderArea: [Object as PropType<dayjs.Dayjs> | null, null],
  startTimeOfRenderArea: [Object as PropType<dayjs.Dayjs> | null, null],
  getPositionOffset: {
    type: Function as PropType<(date: string) => number>,
    required: true
  },
  currentTime: {
    type: Object as PropType<dayjs.Dayjs>,
    required: true
  }
});

const isMinuteScale = (scale: number) => scale < MINUTE_OF_ONE_DAY; // 假设小于一天的分钟数表示分钟级别
const isHourScale = (scale: number) => scale >= MINUTE_OF_ONE_DAY && scale < MINUTE_OF_ONE_DAY * 30; // 假设一个月内的小时数表示小时级别（这个阈值可能需要调整）
const isYearOrGreaterScale = (scale: number) => scale >= MINUTE_OF_ONE_DAY * 30; // 假设一天或更大的单位表示天或更大级别

const startDayOfRenderArea = computed(() => {
  return props.startTimeOfRenderArea ? startOfDay(new Date(props.startTimeOfRenderArea)) : new Date();
});

const endDayOfRenderArea = computed(() => {
  return props.endTimeOfRenderArea ? endOfDay(new Date(props.endTimeOfRenderArea)) : new Date();
});


const paddingWidth = computed(() => {
  const {scale} = props;
  const temp = allDayBlocks.value.find((day) => {
    const dayStart = startOfDay(new Date(day));
    const dayEnd = addDays(dayStart, _isDayScale(scale) ? Math.ceil(scale / MINUTE_OF_ONE_DAY) : 1);
    return isEqual(startDayOfRenderArea.value, dayStart) || isWithinInterval(startDayOfRenderArea.value, dayStart, dayEnd);
  });
  if (!temp || temp === allDayBlocks.value[0]) {
    return 0;
  } else {
    // 假设 getPositionOffset 接受一个日期对象并返回偏移量（这里需要您根据实际情况调整）
    return props.getPositionOffset(temp); // 注意：这里可能需要调整以接受日期对象或转换为字符串
  }
});

// const paddingWidth = computed(() => {
//   const {scale} = props;
//   const temp = allDayBlocks.value.find((day) => {
//     if (
//         scale >= MINUTE_OF_ONE_DAY &&
//         startDayOfRenderArea.value.isBetween(
//             day,
//             day.add(scale / MINUTE_OF_ONE_DAY, 'day')
//         )
//     ) {
//       return true;
//     } else {
//       return day.isSame(startDayOfRenderArea, 'day');
//     }
//   });
//   if (!temp || temp === allDayBlocks.value[0]) {
//     return 0;
//   } else {
//     return props.getPositionOffset(temp.toString());
//   }
// });

const isDayScale = computed(() => _isDayScale(props.scale));

const allDayBlocks = computed(() => {
  const temp = [];
  let {start, end, scale} = props;
  start = startOfDay(new Date(start));
  end = endOfDay(new Date(end));
  let addNum = _isDayScale(scale) && scale > MINUTE_OF_ONE_DAY ? Math.ceil(scale / MINUTE_OF_ONE_DAY) : 1;
  while (isBefore(start, end) || isEqual(start, end)) {
    temp.push(start);
    start = addDays(start, addNum);
  }
  return temp.map(date => date.toISOString()); // 转换为 ISO 字符串以便在模板中使用（如果需要）
});


function getDaysInMonth(month, year) {
  return new Date(year, month + 1, 0).getDate();
}

function isLeapYear(year) {
  return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);
}

const yearsArray = computed(() => {
  const monthYearMap = new Map();

  allDayBlocks.value.forEach(dateStr => {
    const date = new Date(dateStr);
    const year = date.getFullYear();
    const month = date.getMonth() + 1; // 月份从0开始，需要转换为1-12
    const day = date.getDate().toString().padStart(2, '0'); // 格式化日期为两位数

    if (!monthYearMap.has(year)) {
      monthYearMap.set(year, []);
    }

    const yearArray = monthYearMap.get(year);

    let monthObj = yearArray.find(obj => obj.month === month);
    if (!monthObj) {
      monthObj = {month, day: []};
      yearArray.push(monthObj);
    }

    if (!monthObj.day.includes(day)) {
      monthObj.day.push(day);
    }
    // 注意：这里我们不去重，因为您要求的是包含所有日期的数组，
    // 即使某个日期在原始数组中出现多次，也只会在结果数组中出现一次（因为我们用Set或检查包含性来避免重复添加）。
  });

  // 现在，我们需要填充每个月的day数组，使其包含该月的所有日期
  let result = [];
  monthYearMap.forEach((yearArray, year) => {
    yearArray.forEach(monthObj => {
      const daysInMonth = getDaysInMonth(monthObj.month - 1, year); // 月份需要减1以匹配Date对象的索引
      const fullDayArray = Array.from({length: daysInMonth}, (_, i) => (i + 1).toString().padStart(2, '0'));
      monthObj.day = fullDayArray.filter(day => !monthObj.day.includes(day)).concat(monthObj.day);
      // 上面的filter和concat实际上是不必要的，因为我们只需要fullDayArray，
      // 但为了保持与原始逻辑的一致性（尽管有些多余），我保留了它。
      // 正确的做法是直接赋值：monthObj.day = fullDayArray;
      monthObj.day.sort((a, b) => a - b); // 确保日期是排序的（虽然从1到31已经是有序的，但这里为了清晰起见还是加了排序）
    });
    result.push({year, month: yearArray});
  });

  // 由于我们之前保留了不必要的filter和concat操作，现在我们需要清理一下，
  // 只保留fullDayArray的内容，并移除任何可能由于原始数据中的重复日期而产生的多余项（但实际上这里不会有重复项）
  result = result.map(yearObj => ({
    ...yearObj,
    month: yearObj.month.map(monthObj => ({
      ...monthObj,
      day: Array.from({length: getDaysInMonth(monthObj.month - 1, yearObj.year)}, (_, i) => (i + 1).toString().padStart(2, '0'))
    }))
  }));

  // 注意：上面的清理步骤实际上是不必要的，因为我们从未向day数组中添加过重复的日期，
  // 而且我们总是用fullDayArray替换它（尽管在之前的代码中我们并没有真正这么做）。
  // 因此，您可以简化上面的代码，直接赋值fullDayArray到monthObj.day，并省略清理步骤。

  // 这是简化后的代码应该做的：
  /*
  const simplifiedResult = [];
  monthYearMap.forEach((yearArray, year) => {
      const simplifiedYearArray = yearArray.map(monthObj => ({
          month: monthObj.month,
          day: Array.from({ length: getDaysInMonth(monthObj.month - 1, year) }, (_, i) => (i + 1).toString().padStart(2, '0'))
      }));
      simplifiedResult.push({ year, month: simplifiedYearArray });
  });
  return simplifiedResult;
  */

  // 但由于我们已经写出了完整的代码，并且它也能正确工作（尽管有些冗长），
  // 所以这里我们返回原始的、稍微冗长一点的结果。

  return result;
});

console.log(allDayBlocks.value, yearsArray.value)

const cellWidthStyle = computed(() => ({
  width: `${props.cellWidth}px`
}));

const heightStyle = computed(() => ({
  height: props.titleHeight / (isYearOrGreaterScale(props.scale) ? 2 : (isDayScale.value ? 1 : 2)) + 'px',
  lineHeight: props.titleHeight / (isYearOrGreaterScale(props.scale) ? 2 : (isDayScale.value ? 1 : 2)) + 'px'
  // height: props.titleHeight / 2 + 'px',
  // lineHeight: props.titleHeight / 2 + 'px'
}));


// const isInRenderingDayRange = (day: dayjs.Dayjs) => {
//   // 暂时废弃
//   const {scale, currentTime} = props;
//   // let preDay = currentTime.subtract(1, 'day')
//   // let nextDay = currentTime.add(1, 'day')
//   if (
//       scale >= MINUTE_OF_ONE_DAY &&
//       startDayOfRenderArea.value.isBetween(
//           day,
//           day.add(scale / MINUTE_OF_ONE_DAY, 'day')
//       )
//   ) {
//     return true;
//   } else {
//     return startDayOfRenderArea.value.isSameOrBefore(day) && endDayOfRenderArea.value.isSameOrAfter(day);
//   }
// };

// const getTimeScales = (date: string) => {
//   const parsedDate = parseISO(date);
//   const startOfDayDate = startOfDay(parsedDate);
//
//   let timeScales: Date[] = [];
//   let currentTime = startOfDayDate;
//
//   if (isMinuteScale(props.scale)) {
//     // 分钟级别，生成该天内的所有分钟刻度
//     while (isBefore(currentTime, endOfDay(parsedDate)) || isEqual(currentTime, endOfDay(parsedDate))) {
//       timeScales.push(new Date(currentTime));
//       currentTime = addMinutes(currentTime, props.scale);
//     }
//   } else if (isHourScale(props.scale)) {
//     // 小时级别，这里可能需要调整为生成该月内的所有小时刻度（这取决于你的具体需求）
//     // 暂时生成该天内的所有小时刻度作为示例
//     while (isBefore(currentTime, endOfDay(parsedDate)) || isEqual(currentTime, endOfDay(parsedDate))) {
//       timeScales.push(startOfHour(currentTime)); // 假设startOfHour是一个将时间调整到小时开始的函数
//       currentTime = addHours(currentTime, 1); // 这里可能需要调整为更大的时间间隔，如一天或几天
//     }
//     // 注意：上面的逻辑可能需要根据你的需求进行调整，以生成正确的时间刻度
//   } else if (isYearOrGreaterScale(props.scale)) {
//     // 天或更大级别，这里需要生成一个包含所需年月日的时间刻度数组
//     // 这通常涉及到遍历一个日期范围，并根据scale的值（可能是天数、月数等）来决定刻度的间隔
//
//   }
//
//   return timeScales;
// };

const getTimeScales = (date: string) => {
  const parsedDate = parseISO(date);
  if (isSameDay(parsedDate, new Date(props.start))) {
    return generateTimeScale(START_DAY, parsedDate);
  } else if (isSameDay(parsedDate, new Date(props.end))) {
    return generateTimeScale(END_DAY, parsedDate);
  } else {
    return generateTimeScale(MIDDLE_DAY, parsedDate);
  }
};


const generateTimeScale = (type: symbol, date: Date): Date[] => {
  const {start, end, scale} = props;
  let a, b;
  const parsedStart = new Date(start);
  const parsedEnd = new Date(end);

  switch (type) {
    case START_DAY:
      a = getBeginTimeOfTimeLine(dayjs(parsedStart), scale); // 这里我们假设它返回了一个 Date 对象
      b = isSameDay(parsedStart, parsedEnd) ? parsedEnd : endOfDay(parsedStart);
      break;
    case END_DAY:
      a = startOfDay(parsedEnd);
      b = parsedEnd;
      break;
    case MIDDLE_DAY:
      a = startOfDay(date);
      b = endOfDay(date);
      break;
    default:
      throw new TypeError('错误的计算类型');
  }

  const totalBlock: Date[] = [];
  let currentTime = a;
  while (isBefore(currentTime, b) || isEqual(currentTime, b)) {
    totalBlock.push(new Date(currentTime));
    currentTime = addMinutes(currentTime, scale);
  }
  return totalBlock;
};
</script>

<style scoped lang="scss">
/* 您的样式代码 */
.gantt-timeline-year,
.gantt-timeline-month,
.gantt-timeline-day {
  overflow: hidden;
  font-weight: bold;
  color: #666;
  border-right: 1px solid #aaa;
  border-bottom: 1px solid #ddd;
}

.gantt-timeline-scale {
  display: flex;
  border-right: 1px solid #aaa;

  & > div {
    height: 100%;
    font-size: 14px;
    color: #666;
    border-right: 1px solid #ddd;
  }
}
</style>
